#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/if_packet.h> // Ensure this header is included for sockaddr_ll
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>

#define BUFFER_SIZE 1518 // Maximum Ethernet frame size
#define EPOLL_SIZE 1 // Number of file descriptors to monitor

class MyTimer {
public:
    struct timespec start;
    struct timespec end;

    MyTimer()
    {
        clock_gettime(CLOCK_MONOTONIC, &start); // 开始计时
    }

    double elapsed()
    {
        clock_gettime(CLOCK_MONOTONIC, &end); // 开始计时
        double time_taken = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        return time_taken;
    }
};

int main()
{
    int sockfd, epollfd;
    struct ifreq ifr;
    struct sockaddr_ll sa;
    unsigned char buffer[BUFFER_SIZE];
    int numbytes;
    struct epoll_event event, events[EPOLL_SIZE];

    // Create a raw socket
    sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // Specify the network interface to listen on
    strncpy(ifr.ifr_name, "lo", IFNAMSIZ - 1); // Replace "eth0" with your interface name
    if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
        perror("ioctl");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // Prepare sockaddr_ll structure
    memset(&sa, 0, sizeof(sa));
    sa.sll_family = AF_PACKET;
    sa.sll_ifindex = ifr.ifr_ifindex;

    // Bind the socket to the interface
    if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
        perror("bind");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // Create epoll instance
    epollfd = epoll_create1(0);
    if (epollfd < 0) {
        perror("epoll_create1");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // Add the socket file descriptor to the epoll instance
    event.events = EPOLLIN;
    event.data.fd = sockfd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) < 0) {
        perror("epoll_ctl");
        close(sockfd);
        close(epollfd);
        exit(EXIT_FAILURE);
    }

    printf("Listening on interface %s...\n", ifr.ifr_name);
    int recv_pkt = 0;
    MyTimer timer;
    while (1) {
        // Wait for events
        int nfds = epoll_wait(epollfd, events, EPOLL_SIZE, -1);
        if (nfds < 0) {
            perror("epoll_wait");
            close(sockfd);
            close(epollfd);
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < nfds; i++) {
            if (events[i].data.fd == sockfd) {
                // Receive data
                numbytes = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, NULL, NULL);
                if (numbytes < 0) {
                    perror("recvfrom");
                    close(sockfd);
                    close(epollfd);
                    exit(EXIT_FAILURE);
                }

                recv_pkt++;

                if (recv_pkt % 100 == 0) {
                    printf("recvpkt: %d, %.2fKpps\n", recv_pkt, double(recv_pkt) / 1000 / timer.elapsed());
                    // Print received data
                    printf("Received %d bytes\n", numbytes);
                }

                // Print received data
                // printf("Received %d bytes\n", numbytes);

                // Send the received data back
                if (sendto(sockfd, buffer, numbytes, 0, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
                    perror("sendto");
                    close(sockfd);
                    close(epollfd);
                    exit(EXIT_FAILURE);
                }

                // printf("Sent %d bytes back\n", numbytes);
            }
        }
    }

    close(sockfd);
    close(epollfd);
    return 0;
}
